/*
 * $Id: $
 */
package org.rcgwt.client.ui.grid.renderer;

import org.rcgwt.client.ui.grid.internal.model.ICellModel;
import org.rcgwt.client.ui.grid.internal.model.IElementModel;
import org.rcgwt.client.ui.grid.internal.model.IGroupModel;
import org.rcgwt.client.ui.grid.internal.model.IHeaderModel;
import org.rcgwt.client.ui.grid.internal.model.IElementModelDelta;
import org.rcgwt.client.ui.grid.internal.model.IRowModel;
import org.rcgwt.client.ui.grid.internal.model.IStateMasks;
import org.rcgwt.client.ui.grid.internal.model.ITitleCellModel;
import org.rcgwt.client.ui.grid.internal.model.ITitleRowModel;
import org.rcgwt.client.ui.grid.internal.model.IViewModel;
import org.rcgwt.client.ui.grid.internal.model.IViewModelElements;
import org.rcgwt.client.ui.grid.theme.CssStyle;
import org.rcgwt.client.ui.grid.theme.IGridTheme;

import com.google.gwt.dom.client.Element;
import com.google.gwt.user.client.ui.impl.FocusImpl;

/**
 * 
 * @author Olivier Oeuillot (latest modification by $Author: $)
 * @version $Revision: $ $Date: $
 */
abstract class AbstractRenderer<T extends IElementModel> {

    static final FocusImpl impl = FocusImpl.getFocusImplForPanel();

    public void processDelta(IViewRenderContext viewRenderContext,
            Element element, IElementModelDelta<T> modelElementDelta) {

        T modelElement = modelElementDelta.getModelElement();

        if (modelElementDelta.hasStateMaskChanged()) {

            int masks = modelElementDelta.getMask();
            int bits = modelElementDelta.getBits();

            if (masks != ~IStateMasks.SHOW_STATE_MASK) {
                updateStateMask(viewRenderContext, element, modelElement);
            }

            if ((bits & IStateMasks.SHOW_STATE_MASK) > 0) {
                show(viewRenderContext, element, modelElement);
            }

        }

        if (modelElementDelta.hasContentChanged()) {
            updateContent(viewRenderContext, element, modelElement);
        }

        processDelta(viewRenderContext, modelElementDelta);
    }

    protected void show(IViewRenderContext viewRenderContext, Element element,
            T modelElement) {
    }

    public void update(IViewRenderContext viewRenderContext, Element element,
            T modelElement, int renderedIndex) {
        updateContent(viewRenderContext, element, modelElement);

        updateStateMask(viewRenderContext, element, modelElement);
    }

    protected abstract void updateContent(IViewRenderContext viewRenderContext,
            Element element, T modelElement);

    protected void updateStateMask(IViewRenderContext viewRenderContext,
            Element element, T modelElement) {

        CssStyle cssStyle = getCssStyle(viewRenderContext, modelElement);
        if (cssStyle != null) {
            element.setClassName(cssStyle.getClassName());
        }

    }

    protected CssStyle getCssStyle(IViewRenderContext viewRenderContext,
            T modelElement) {
        return null;
    }

    @SuppressWarnings( { "unchecked", "incomplete-switch" })
    protected static void processDelta(IViewRenderContext viewRenderContext,
            IElementModelDelta< ? > modelElementDelta) {
        IGridRenderContext gridRenderContext = viewRenderContext
                .getGridRenderContext();
        IViewModel viewModel = viewRenderContext.getViewModel();
        IViewModelElements viewModelElements = viewModel.getViewModelElements();

        IGridTheme theme = viewRenderContext.getGridRenderContext().getTheme();

        IElementModelDelta< ? extends IElementModel> deltas[] = modelElementDelta
                .listChildrenDeltas();

        for (IElementModelDelta< ? extends IElementModel> delta : deltas) {
            if (delta == null) {
                continue;
            }

            IElementModel child = delta.getModelElement();

            switch (child.getType()) {
            case CELL:
                ICellModel cell = (ICellModel) child;

                Element cellElement = viewModelElements.getCellElement(
                        gridRenderContext, cell);
                if (cellElement == null) {
                    continue;
                }

                IRenderer<ICellModel> cellRenderer = theme
                        .getCellRenderer(cell);

                cellRenderer.processDelta(viewRenderContext, cellElement,
                        (IElementModelDelta<ICellModel>) delta);
                break;

            case ROW:
                IRowModel row = (IRowModel) child;

                Element rowElement = viewModelElements.getRowElement(row);
                if (rowElement == null) {
                    continue;
                }

                IRowRenderer rowRenderer = theme.getRowRenderer(row);

                rowRenderer.processDelta(viewRenderContext, rowElement,
                        (IElementModelDelta<IRowModel>) delta);
                break;

            case GROUP:
                IGroupModel groupModel = (IGroupModel) child;

                Element groupElement = viewModelElements
                        .getGroupElement(groupModel);
                if (groupElement == null) {
                    continue;
                }

                IGroupRenderer groupRenderer = theme
                        .getGroupRenderer(groupModel);

                groupRenderer.processDelta(viewRenderContext, groupElement,
                        (IElementModelDelta<IGroupModel>) delta);
                break;

            case TITLE_ROW:
                ITitleRowModel titleRow = (ITitleRowModel) child;

                Element titleRowElement = viewModelElements
                        .getTitleRowElement(titleRow);
                if (titleRowElement == null) {
                    continue;
                }

                ITitleRowRenderer titleRowRenderer = theme
                        .getTitleRowRenderer(titleRow);

                titleRowRenderer.processDelta(viewRenderContext,
                        titleRowElement,
                        (IElementModelDelta<ITitleRowModel>) delta);
                break;

            case TITLE_CELL:
                ITitleCellModel titleCell = (ITitleCellModel) child;

                Element titleCellElement = viewModelElements
                        .getTitleCellElement(titleCell);
                if (titleCellElement == null) {
                    continue;
                }

                ITitleCellRenderer titleCellRenderer = theme
                        .getTitleCellRenderer(titleCell);

                titleCellRenderer.processDelta(viewRenderContext,
                        titleCellElement,
                        (IElementModelDelta<ITitleCellModel>) delta);
                break;

            case HEADER:
                IHeaderModel header = (IHeaderModel) child;

                Element headerElement = viewModelElements
                        .getHeaderElement(header);
                if (headerElement == null) {
                    continue;
                }

                IHeaderRenderer headerRenderer = theme
                        .getHeaderRenderer(header);

                headerRenderer.processDelta(viewRenderContext, headerElement,
                        (IElementModelDelta<IHeaderModel>) delta);
                break;

            case COLUMN:
                // RIEN ....
                break;

            case VIEW:
            case GRID:
                // RIEN
                break;
            }
        }
    }

    protected final void processDelta(IGridRenderContext gridRenderContext,
            IElementModelDelta< ? > modelElementDelta) {

        IGridTheme theme = gridRenderContext.getTheme();

        IElementModelDelta< ? extends IElementModel> deltas[] = modelElementDelta
                .listChildrenDeltas();

        for (IElementModelDelta< ? extends IElementModel> delta : deltas) {
            if (delta == null) {
                continue;
            }

            IElementModel child = delta.getModelElement();

            switch (child.getType()) {

            case VIEW:
                IViewModel viewModel = (IViewModel) child;

                Element viewElement = viewModel.getViewModelElements()
                        .getViewElement();
                if (viewElement == null) {
                    continue;
                }

                IViewRenderer viewRenderer = theme.getViewRenderer(viewModel);

                IViewRenderContext viewRendererContext = gridRenderContext
                        .getViewRenderContext(viewModel);

                viewRenderer.processDelta(viewRendererContext, viewElement,
                        (IElementModelDelta<IViewModel>) delta);
                break;
            }
        }
    }

    protected final com.google.gwt.user.client.Element toElement(Element element) {
        return (com.google.gwt.user.client.Element) element;
    }

    public int[] getSizes(IViewRenderContext viewRenderContext,
            Element element, T modelElement, int sizes[]) {
        if (sizes == null || sizes.length < 2) {
            sizes = new int[2];
        }

        sizes[0] = element.getOffsetWidth();
        sizes[1] = element.getOffsetHeight();

        return sizes;
    }

}
